﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.IO;
using System.Resources;
using System.Threading;
using Microsoft.Phone.Scheduler;
using MusicAlarm7.Resources;


namespace MusicAlarm7.Model
{
    public class AlarmDataContext : DataContext
    {
        public AlarmDataContext(string connectionString) : base(connectionString) { }

        /// <summary>
        /// 所有闹铃项目的集合
        /// </summary>
        public Table<AlarmItem> Items;

        /// <summary>
        /// 闹铃项目与系统闹铃对象对应关系集合
        /// </summary>
        public Table<AlarmNotification> Notifications;
    }

    [Table]
    public class AlarmItem : INotifyPropertyChanged, INotifyPropertyChanging
    {
        //Binary 版本列（具有 [Column(IsVersion = true)] 属性）显著改进表的更新性能。
        [Column(IsVersion = true)]
        private Binary _version;
        private int _alarmId;
        private DateTime _alarmTime;
        //private IList _recurringDays;
        private string _content = string.Empty;
        private Uri _music = null;
        private int _musicIndex = -1;
        private EntitySet<AlarmNotification> _alarmNoti;
        //private Uri _musicDir = new Uri("/Tune", UriKind.Relative);

        public AlarmItem()
        {
            _alarmNoti = new EntitySet<AlarmNotification>(
                new Action<AlarmNotification>(this.attach_alarmNoti),
                new Action<AlarmNotification>(this.detach_alarmNoti)
                );
        }

        public void SetAlarm()
        {
            foreach (AlarmNotification a in this.Notifications)
            {
                a.SetAlarm();
            }
        }

        public void UnsetAlarm()
        {
            foreach (AlarmNotification a in this.Notifications)
            {
                a.UnsetAlarm();
            }
        }

        private void attach_alarmNoti(AlarmNotification noti)
        {
            NotifyPropertyChanging("Notifications");
            noti.AlarmItem = this;
            NotifyPropertyChanged("Notifications");
        }

        private void detach_alarmNoti(AlarmNotification noti)
        {
            NotifyPropertyChanging("Notifications");
            noti.AlarmItem = null;
            NotifyPropertyChanged("Notifications");
        }

        /// <summary>
        /// 闹铃的唯一标识符
        /// </summary>
        [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
        public int AlarmId
        {
            get { return _alarmId; }
            set
            {
                if (_alarmId != value)
                {
                    NotifyPropertyChanging("AlarmId");
                    _alarmId = value;
                    NotifyPropertyChanged("AlarmId");
                }
            }
        }

        /// <summary>
        /// 闹铃的响铃时间
        /// </summary>
        [Column]
        public DateTime AlarmTime
        {
            get { return _alarmTime; }
            set
            {
                if (_alarmTime != value)
                {
                    NotifyPropertyChanging("AlarmTime");
                    NotifyPropertyChanging("Eta");
                    _alarmTime = value;
                    NotifyPropertyChanged("AlarmTime");
                    NotifyPropertyChanged("Eta");
                }
            }
        }

        public TimeSpan Eta
        {
            get
            {
                DateTime now = DateTime.Now;
                TimeSpan sp = TimeSpan.Zero;

                if (!this._isEnabled) { return TimeSpan.Zero; }

                foreach (AlarmNotification noti in this.Notifications)
                {
                    TimeSpan spd = noti.NextAlarm - now;
                    if ((spd < sp && spd > TimeSpan.Zero) || sp <= TimeSpan.Zero)
                    {
                        sp = spd;
                    }
                }
                return sp;
            }
        }

        [Column]
        private string _recurringDays = "0000000";
        /// <summary>
        /// 闹铃的响铃日期。
        /// </summary>
        public string RecurringDays
        {
            get { return this._recurringDays; }
            set
            {
                if (value.Length != 7)
                {
                    throw new ArgumentException("Invalid days value: " + this._recurringDays);
                }
                foreach (char c in value.ToCharArray())
                {
                    if (c != '0' && c != '1')
                    {
                        throw new ArgumentException("Invalid days value: " + this._recurringDays);
                    }
                }

                bool cycle = false;

                NotifyPropertyChanging("RecurringDays");
                NotifyPropertyChanging("Eta");

                if (this.IsEnabled) this.UnsetAlarm();
                this.Notifications.Clear();
                this._recurringDays = value;

                for (int i = 0; i < 7; i++)
                {
                    if (value[i] == '1')
                    {
                        AlarmNotification noti = new AlarmNotification(i);
                        this.Notifications.Add(noti);
                        cycle = true;
                    }
                }
                if (!cycle)
                {
                    AlarmNotification noti = new AlarmNotification();
                    this.Notifications.Add(noti);
                }

                NotifyPropertyChanged("RecurringDays");
                NotifyPropertyChanged("Eta");
            }
        }


        [Column]
        public int MusicIndex
        {
            get
            {
                return this._musicIndex;
            }
            set
            {
                if (this._musicIndex != value)
                {
                    NotifyPropertyChanging("MusicIndex");
                    NotifyPropertyChanging("Music");
                    NotifyPropertyChanging("MusicName");
                    this._musicIndex = value;
                    if (value == -1)
                    {
                        this._music = null;
                    }
                    else
                    {
                        this._music = new Uri("Tune/" + Musics[this._musicIndex], UriKind.Relative);
                    }
                    NotifyPropertyChanged("MusicIndex");
                    NotifyPropertyChanged("Music");
                    NotifyPropertyChanged("MusicName");
                }
            }
        }

        public Uri Music
        {
            get { return _music; }
        }

        public string MusicName
        {
            get { return Path.GetFileNameWithoutExtension(this.Music.ToString()); }
        }

        private static ObservableCollection<string> _musics = null;
        public static ObservableCollection<string> Musics
        {
            get
            {
                if (_musics == null)
                {
                    int i = 1;
                    string s;
                    _musics = new ObservableCollection<string>();
                    do
                    {
                        try
                        {
                            s = AppResources.ResourceManager.GetString("Tune" + i++);
                            if (s == null) break;
                            _musics.Add(s);
                        }
                        catch (MissingManifestResourceException) { break; }
                    } while (s != null);
                }
                return _musics;
            }
        }

        [Column]
        private bool _isEnabled = true;
        public bool IsEnabled
        {
            get
            {
                if (this.RecurringDays == "0000000")
                {
                    try
                    {
                        ScheduledAction alarm = ScheduledActionService.Find(this.Notifications[0].Name);
                        this._isEnabled = alarm.BeginTime > DateTime.Now;
                    }
                    catch (Exception)
                    {
                        this._isEnabled = false;
                    }
                    NotifyPropertyChanged("Eta");
                }
                return _isEnabled;
            }
            set
            {
                if (_isEnabled != value)
                {
                    NotifyPropertyChanging("IsEnabled");
                    NotifyPropertyChanging("Eta");
                    if (value)
                    {
                        this.SetAlarm();
                    }
                    else
                    {
                        this.UnsetAlarm();
                    }
                    _isEnabled = value;
                    NotifyPropertyChanged("IsEnabled");
                    NotifyPropertyChanged("Eta");
                }
            }
        }

        /// <summary>
        /// 响铃时的提示信息
        /// </summary>
        [Column]
        public string Content
        {
            get { return _content; }
            set
            {
                if (_content != value)
                {
                    NotifyPropertyChanging("Content");
                    _content = value;
                    NotifyPropertyChanged("Content");
                }
            }
        }

        /// <summary>
        /// 返回该闹铃项目关联的系统Alarm对象
        /// </summary>
        [Association(Storage = "_alarmNoti", OtherKey = "_alarmId", ThisKey = "AlarmId", DeleteRule = "CASCADE")]
        public EntitySet<AlarmNotification> Notifications
        {
            get { return this._alarmNoti; }
            set { this._alarmNoti.Assign(value); }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion

    }

    [Table]
    public class AlarmNotification : INotifyPropertyChanged, INotifyPropertyChanging
    {
        //Binary 版本列（具有 [Column(IsVersion = true)] 属性）显著改进表的更新性能。
        [Column(IsVersion = true)]
        private Binary _version;
        private string _name;
        private Nullable<DayOfWeek> _day;
        [Column]
        internal int _alarmId;
        private EntityRef<AlarmItem> _alarmItem;

        public AlarmNotification(int dayOfWeek)
            : this()
        {
            this._day = (DayOfWeek)dayOfWeek;
        }


        public AlarmNotification()
        {
            this._name = System.Guid.NewGuid().ToString();
            this._day = null;
        }

        public static DayOfWeek ParseDayOfWeek(string dayOfWeek)
        {
            DateTime today = DateTime.Today;
            DateTime d;

            System.Diagnostics.Debug.WriteLine("The current culture is {0}.\n", Thread.CurrentThread.CurrentCulture.Name);

            for (int i = 0; i < 7; i++)
            {
                d = today.AddDays(i);
                if (d.ToString("dddd") == dayOfWeek)
                {
                    return d.DayOfWeek;
                }
            }

            throw new ArgumentOutOfRangeException("dayOfWeek", "Can not find name \"" + dayOfWeek + "\" in current culture: " + Thread.CurrentThread.CurrentCulture.Name);
        }

        public void SetAlarm()
        {
            this.UnsetAlarm();

            Alarm alarm = new Alarm(this.Name)
            {
                BeginTime = this.NextAlarm,
                Content = this.AlarmItem.Content,
                Sound = this.AlarmItem.Music,
                RecurrenceType = this.Day != null ? RecurrenceInterval.Weekly : RecurrenceInterval.None
            };

            ScheduledActionService.Add(alarm);
        }

        public void UnsetAlarm()
        {
            try
            {
                ScheduledActionService.Remove(this.Name);
            }
            catch (InvalidOperationException) { }
        }

        public DateTime NextAlarm
        {
            get
            {
                DateTime now = DateTime.Now;
                int day = 0;

                if (this.Day != null)
                    day = (DayOfWeek)this.Day - now.DayOfWeek;
                else if (now.TimeOfDay >= this.AlarmItem.AlarmTime.TimeOfDay)
                    ++day;
                if (day < 0) day += 7;
                return now.Date.AddDays(day) + this.AlarmItem.AlarmTime.TimeOfDay;
            }
        }

        /// <summary>
        /// 闹铃在系统中的唯一标识符
        /// </summary>
        [Column(IsPrimaryKey = true, IsDbGenerated = false, CanBeNull = false)]
        public string Name
        {
            get { return _name; }
            set
            {
                if (_name != value)
                {
                    NotifyPropertyChanging("Name");
                    _name = value;
                    NotifyPropertyChanged("Name");
                }
            }
        }

        /// <summary>
        /// 当前Notification对象表示的每周日期
        /// </summary>
        [Column(CanBeNull = true)]
        public Nullable<DayOfWeek> Day
        {
            get { return _day; }
            set
            {
                if (_day != value)
                {
                    NotifyPropertyChanging("Day");
                    _day = value;
                    NotifyPropertyChanged("Day");
                }
            }
        }


        /// <summary>
        /// 返回关联的闹铃项目的引用
        /// </summary>
        [Association(Storage = "_alarmItem", ThisKey = "_alarmId", OtherKey = "AlarmId", DeleteRule = "CASCADE", IsForeignKey = true)]
        public AlarmItem AlarmItem
        {
            get { return _alarmItem.Entity; }
            set
            {
                NotifyPropertyChanging("AlarmItem");
                _alarmItem.Entity = value;
                if (value != null)
                {
                    _alarmId = value.AlarmId;
                }
                NotifyPropertyChanged("AlarmItem");
            }
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion
    }

    //public class MusicIndexConverter : IValueConverter
    //{
    //    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    //    {
    //        return (int)value;
    //    }

    //    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    //    {
    //        return (int)value;
    //    }
    //}
}
